
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;

using Swaf;
using Swaf.BizObj;
using Swaf.Gui;
using Swaf.Security;

[assembly: WebResource("Syrinx.Gui.AspNet.NitobiCtls.nitobi.combo.v2.js", "application/x-javascript")]

namespace Syrinx.Gui.AspNet.NitobiCtls
{
	[ParseChildren(false)]
	public class NitobiComboBoxBizObjListDisplay : Swaf.Gui.AspNet2.UserControl, INamingContainer, IGridBizObjListDisplay, IWidget, IPostBackEventHandler, INitobiClientControl
	{
		protected ExtendedNitobiCombo m_combo;
		protected Privileges m_editPriv = Privileges.ReadOnly;
		protected int m_maxElements = -1;
		protected XmlElement m_layoutTemplate = null;
		protected IBizObjList m_bizobjList = null;
		protected IBizObj m_selectedBizObj = null;
		protected string m_viewField = "";

		protected string m_dataSourceBizRule = null;
		protected object m_dataSourceBizRuleParam = null;
		protected string m_dataSourceId = null;
		protected string m_listWidth = null, m_textBoxWidth = null, m_listHeight = null;
		protected bool m_liveScroll = true;
		protected bool m_comboDataSourceSetup = false;
		protected bool m_autoTrigger = false;
		protected bool m_autoPostBack = false;
		protected bool m_drivesBizProc = true;

		public string DataSourceBizRule { get { return m_dataSourceBizRule; } set { m_dataSourceBizRule = value; } }
		public object DataSourceBizRuleParam { get { return m_dataSourceBizRuleParam; } set { m_dataSourceBizRuleParam = value; } }
		public string DsId { get { return m_dataSourceId; } set { m_dataSourceId = value; } }
		public bool LiveScroll { get { return true;/* m_liveScroll;*/ } set { m_liveScroll = value; } }
		public bool AutoTrigger { get { return m_autoTrigger; } set { m_autoTrigger = value; } }
		public bool AutoPostBack { get { return m_autoPostBack; } set { m_autoPostBack = value; m_autoTrigger = value; } }
		public bool DrivesBizProc { get { return m_drivesBizProc; } set { m_drivesBizProc = value; } }

		public NitobiComboBoxBizObjListDisplay()
			:base()
		{
		}

		public NitobiComboBoxBizObjListDisplay(ActiveWidget widget)
			:base(widget)
		{
		}

		protected override void OnLoad(EventArgs e)
		{
			setupCombo();
			base.OnLoad(e);

			if (m_createOnLoad)
			{
				if (!(BPC.ActiveWidgets.ContainsKey(WidgetId)))
				{
					WidgetOfflineState offlineState = State;
					ActiveWidget act = new ActiveWidget(this, BPC, offlineState);
					BPC.defineActiveWidget(act);
					if (offlineState.State.get("m_autoTrigger") == null)
						offlineState.State.put("m_autoTrigger", m_autoTrigger);
					if (offlineState.State.get("m_autoPostBack") == null)
						offlineState.State.put("m_autoPostBack", m_autoTrigger);
					if (offlineState.State.get("m_drivesBizProc") == null)
						offlineState.State.put("m_drivesBizProc", m_autoTrigger);
				}
			}

		}
		public override string ContentName {get{return null;}}
		protected override System.IO.TextReader Html {get{return null;}}
		public IBizObjList BizObjs
		{
			get
			{
				if (BPC == null)
					return null;
				ActiveBizProc bizproc = (State.ParentBizProcIds.Count == 0) ? null : BPC.getActiveBizProc(State.ParentBizProcIds[0]);
				if (DataSourceBizRule != null)
				{
					string ruleName = DataSourceBizRule;
					Regex r2 = new Regex(@"(.*?)\[(.*?)\]", RegexOptions.IgnoreCase);
					Match m2 = r2.Match(ruleName);
					string brParam = null;
					if (m2.Success)
					{
						ruleName = m2.Groups[1].Value;
						brParam = m2.Groups[2].Value;
						if (string.Compare(brParam, "ParentBizProcId", true) == 0)
							brParam = bizproc.OfflineState.Id;
						else if (string.Compare(brParam, "ParentParentBizProcId", true) == 0)
							brParam = bizproc.OfflineState.Id; //m_parentBizProc.ParentBizProc.Parent.Id;
					}
					IResults rc = brParam == null ? App.ruleMgr.execute(ruleName) : App.ruleMgr.execute(ruleName, brParam);
					return rc.CallResults as IBizObjList;
				}
				else if(bizproc != null && bizproc.BizProc != null)
				{
					return bizproc.BizProc.SourceBizObjs;
				}
				return null;
			}
		}

		public IApplication App { get { return Application.currentApp; } }

		#region IBizObjListDisplay Members

		public event BizObjChanged BizObjAdded;

		public event BizObjChanged BizObjDeleted;

		public event BizObjSelectedInfo BizObjSelected;

		public event BizObjChanged BizObjUpdated;

		public Swaf.Security.Privileges EditPrivilege
		{
			get
			{
				return Privileges.None;
			}
			set
			{
			}
		}

		public int MaxElements
		{
			get
			{
				return -1;
			}
			set
			{
			}
		}


		public string ListWidth { get { return m_listWidth; } set { m_listWidth = value; } }
		public string ListHeight { get { return m_listHeight; } set { m_listHeight = value; } }
		public string TextBoxWidth { get { return m_textBoxWidth; } set { m_textBoxWidth = value; } }

		public IBizObj SelectedBizObj
		{
			get
			{
				if (m_combo != null && BizObjs != null)
				{
					int row = m_combo.SelectedRowIndex;
					if (row >= 0)
						m_selectedBizObj = m_bizobjList[row];
				}
				return m_selectedBizObj;
			}
			set
			{
				m_selectedBizObj = value;
			}
		}

		public object SelectedBizObjKeyValue
		{
			get
			{
				IBizObj sel = SelectedBizObj;
				return sel == null ? null : sel.KeyValue;
			}
			set 
			{
				if (value == null)
				{
					m_selectedBizObj = null;
					return;
				}
				IBizObjList bizobjs = BizObjs;
				if (bizobjs != null)
					SelectedBizObj = bizobjs.search(bizobjs.objectType.KeyFieldNames, value);
			} 
		}

		public void getSelectedBizObjs(IBizObjList selected)
		{
			IBizObj sel = SelectedBizObj;
			if (sel != null)
				selected.Add(sel);
		}
		public void setSelectedBizObjs(IBizObjList selected)
		{
		}

		public void showBizObjs(IBizObjCursor cur)
		{
			m_bizobjList = cur.Source;
			setupCombo();
			//setupStateInfo();
		}

		public virtual void updateBizObjs()
		{
			//Intentionally left blank. This class is read only.
		}

		#endregion

		#region IWidget Members

		#endregion

		#region ILayoutTemplateHandler Members

		public XmlElement LayoutTemplate
		{
			get
			{
				return m_layoutTemplate;
			}
			set
			{
				m_layoutTemplate = value;
			}
		}

		#endregion

		public string ColumnNames
		{
			get
			{
				if (m_layoutTemplate == null) return "";

				StringBuilder buff = new StringBuilder();
				foreach (XmlNode node in m_layoutTemplate.ChildNodes)
					if (node is XmlElement && "column".CompareTo(node.Name.ToLower()) == 0)
						buff.Append(((XmlElement)node).GetAttribute("field")).Append("|");
				return buff.ToString(0, buff.Length - 1);
			}
		}

		public static void setupGlobalScripts(Page p)
		{
			string scriptUrl = p.ClientScript.GetWebResourceUrl(typeof(NitobiComboBoxBizObjListDisplay), "Syrinx.Gui.AspNet.NitobiCtls.nitobi.combo.v2.js");
			p.ClientScript.RegisterClientScriptInclude("Nitobi.ComboScript", scriptUrl);
			p.ClientScript.RegisterClientScriptBlock(typeof(NitobiComboBoxBizObjListDisplay), "GlobalCombo", s_globalScript, true);

		}

		protected override void OnPreRender(EventArgs e)
		{
			CreateChildControls();
			base.OnPreRender(e);
			setupGlobalScripts(Page);

		}
		protected override void Render(HtmlTextWriter writer)
		{
			base.Render(writer);

			ActiveBizProc bizproc = (State.ParentBizProcIds.Count == 0) ? null : BPC.getActiveBizProc(State.ParentBizProcIds[0]);
			string mainId = UniqueID.Replace("$", "");
			string triggerHandler = "";
			string innerReg = "";
			string registerScript = "";
			object selectedKey = "";
			object selectedValue = "";
			if (SelectedBizObj != null)
			{
				selectedKey = SelectedBizObj.KeyValue;
				if (m_viewField != null && m_viewField != "")
					selectedValue = SelectedBizObj.get(m_viewField);
			}
			if (bizproc != null && m_drivesBizProc)
			{
				triggerHandler = string.Format(s_triggerScript, bizproc.OfflineState.Id, ClientID);
				innerReg = string.Format(s_innerRegisterScript, bizproc.OfflineState.Id, ClientID, m_viewField);
			}
			else if (m_autoTrigger)
				triggerHandler = string.Format(s_updateTriggerScript, ClientID);

			registerScript = string.Format(s_registerScript, m_combo.ClientID, selectedKey, innerReg, selectedValue == null ? "" : selectedValue.ToString().Replace("'", "\\'"));
			//writer.Write(s_perControlScript, mainId, m_combo.ClientID,
			//    Page.ClientScript.GetPostBackEventReference(this, "Select"), triggerHandler, registerScript, m_combo.ClientID.Replace('$', '_'));
			writer.Write(s_perControlScript, mainId, m_combo.ClientID,
				"__doPostBack('" + this.UniqueID + "', getSelectedRowKey(nitobi.getComponent('" + m_combo.ClientID + "')))",
				triggerHandler, registerScript, m_combo.ClientID.Replace('$', '_'),
				m_autoPostBack.ToString().ToLower());
		}

		protected void setupCombo()
		{
			if (m_combo == null)
			{
				m_combo = new ExtendedNitobiCombo(this);
				m_combo.ID = "cm";

				m_combo.Mode = Nitobi.Combo.ModeType.Classic;
				m_combo.List.AllowPaging = false;
				m_combo.ComboSourceURL = "";
				m_combo.ToolkitSourceURL = "";
				m_combo.StylesheetURL = "";
				m_combo.Theme = "Vista";
				m_combo.List.CustomHTMLDefinition = "${1}";
				m_combo.List.HighlightCSSClassName = "ComboBoxListBodyTableRowHighlighted"; //wendell@syrinx.ph: for theme color
				setupColumns();
				//m_combo.List.Width = "300px";
				//m_combo.Width = new Unit("300px");
				if (m_textBoxWidth != null)
					m_combo.TextBox.Width = m_textBoxWidth;
				if (m_listWidth != null)
					m_combo.List.Width = m_listWidth;
				if (m_listHeight != null)
					m_combo.List.Height = m_listHeight;
				setupComboDataSource();

				m_combo.TextBox.DataFieldIndex = 1;
				m_combo.OnSelectEvent = string.Format("ComboRowSelected{0}()", UniqueID.Replace("$", ""));
				m_combo.HttpRequestMethod = Nitobi.Combo.HttpRequestMethodType.Get;
				Controls.Add(m_combo);
			}
		}

		protected virtual void setupComboDataSource()
		{
			if (!LiveScroll || m_comboDataSourceSetup || m_combo == null)
			{
				//Without setting the datasourceurl to something bogus, on first page load when a compile is happening, 
				//the combo asks for the anyway.  The combo client script now checks for the datasourceurl == 'x' and if it is
				//Stops the request for data like that.
				if(!LiveScroll && m_combo != null)
					m_combo.List.DatasourceUrl = "x";
				return;
			}

			try
			{
				ActiveBizProc bizproc = (State.ParentBizProcIds.Count == 0) ? null : BPC.getActiveBizProc(State.ParentBizProcIds[0]);
				m_comboDataSourceSetup = true;
				string dataUrl = string.Format("/NitiboLiveStreamHandler.aspx?pi={0}&cl={1}&RequestType=Get", BPC.PageState.PageId, ColumnNames);
				dataUrl = Page.Response.ApplyAppPathModifier(dataUrl);
				if (bizproc != null)
					m_combo.List.DatasourceUrl = dataUrl = dataUrl + "&bpi=" + bizproc.OfflineState.Id;
				else if(DataSourceBizRule == null)
					m_comboDataSourceSetup = false;
				if (DataSourceBizRule != null)
					m_combo.List.DatasourceUrl = dataUrl = dataUrl + "&br=" + DataSourceBizRule;
			}
			catch (Exception)
			{
				m_comboDataSourceSetup = false;
			}
		}

		protected void setupColumns()
		{
			if (m_layoutTemplate != null)
			{
				int index = 0;
				foreach (XmlNode node in m_layoutTemplate.ChildNodes)
					if (node is XmlElement)
					{
						XmlElement child = (XmlElement)node;
						if ("column".CompareTo(child.Name.ToLower()) == 0)
						{
							string fieldName = child.GetAttribute("field");
							if (index == 1)
								m_viewField = fieldName;
							string label = child.GetAttribute("label");
							int width = 0;
							int.TryParse(child.GetAttribute("width"), out width);
							bool visible = string.Compare(child.GetAttribute("visible"), "false", true) != 0;
							m_combo.ListColumnDefinitionItems.Add(new Nitobi.ListColumnDefinition(label, index++));
						}
					}
			}
		}

		protected virtual string calcDataSourceId()
		{
			return m_dataSourceId == null ? ClientID : m_dataSourceId;
		}
		protected override void AddParsedSubObject(object obj)
		{
			System.Web.UI.LiteralControl control = (System.Web.UI.LiteralControl)obj;
			XmlDocument doc = new XmlDocument();
			doc.LoadXml(control.Text == "" ? "<Empty/>" : control.Text);
			this.LayoutTemplate = doc.DocumentElement;
		}

		public void RaisePostBackEvent(string eventArgument)
		{
			ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
			bizproc.BizProc.selectBizObj(eventArgument, this);
		}

		#region INitobiList Members

		public string RefreshListScript
		{
			get { return ""; }
		}

		public string getRefreshAndSetSelectedScript(int selectedRow)
		{ return ""; }

		#endregion

		#region INitobiClientControl Members

		public bool NeedToGenerateHtmlWithServerControls { get { return false; } }


		public void setState(XmlElement clientState)
		{
			int selectedRow = 0;
			if (int.TryParse(clientState.GetAttribute("selected"), out selectedRow))
			{
				setupCombo();
				m_combo.SelectedRowIndex = selectedRow;
			}
		}

		public void getState(XmlElement clientState, string pageHtml)
		{
			IBizObj selected = SelectedBizObj;
			if(LiveScroll && selected != null)
				clientState.SetAttribute("refresh", selected.KeyValue.ToString());
		}

		public void processAjaxEvent(XmlElement eventInfo)
		{
			if (eventInfo.GetAttribute("event").CompareTo("bizObjSelected") == 0)
			{
				string bizObjId = eventInfo.GetAttribute("value");
				processBizObjSelected(bizObjId);
			}
			else if (eventInfo.GetAttribute("event").CompareTo("bizObjFieldSelected") == 0)
			{
				//ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
				string bizProcIds = State.State.get("ParentControlBizProcIds") as string;
				if (bizProcIds != null)
				{
					ActiveBizProc bizproc = BPC.getActiveBizProc(bizProcIds.Split(',')[0]);
					bizproc.BizProc.updateBizObj(true);
				}
			}
		}

		protected virtual void processBizObjSelected(string bizObjId)
		{
			ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
			bizproc.BizProc.selectBizObj(bizObjId, this);
		}

		protected bool m_createOnLoad = true;
		public bool CreateOnLoad{set { m_createOnLoad = value; }}
		public override BizProcWidgetType BizProcWidgetType {get{return BizProcWidgetType.list;}set{}}
		#endregion


		protected static string s_globalScript = @"
var combos = new Array();
function OnAfterIntializeEbaCombos()
{
	for(var p = 0; p < combos.length;p++)
	{
		var combo = nitobi.getComponent(combos[p]);
		if(combo.GetList().GetDatasourceUrl() != 'x')
		{
			combo.GetList().GetPage(0, 0);
			combo.GetList().SetSelectedRowIndex(-1);
		}
		try{
			var e = combos[p] + 'Setup()'; //.replace(/\$/g,'_')
			eval(e)
		}catch(e){}
	}
}
function setSelectedRowByKey(combo, key)
{
//debugger;
	var ds =combo.GetList().GetXmlDataSource();	
	var numRows = ds.GetNumberRows();
	for(var p = 0; p < numRows; p++)
		if(ds.GetRow(p)[0] == key)
		{
			window.document.getElementById(combo.GetId()+'SelectedRowIndex').value = p;
			combo.GetList().SetSelectedRow(p);
			combo.SetTextValue(ds.GetRow(p)[1]);
			break;
		}
}
function getSelectedRowKey(combo)
{
//debugger;
	var ds =combo.GetList().GetXmlDataSource();	
	var index = combo.GetList().GetSelectedRowIndex();
	if(index == -1)
		index = window.document.getElementById(combo.GetId()+'SelectedRowIndex').value;
	var numRows = ds.GetNumberRows();
	return (index == null || index < 0 || numRows == 0)?null:ds.GetRow(index)[0];
}
function setComboState(stateEl)
{
	var refresh = stateEl.getAttribute('refresh');
	if(refresh != '')
	{
		this.lastKey = refresh;
		this.dhtmlObj.GetList()._syx = this;
		this.dhtmlObj.GetList().GetPage(0, 0, null,0, null, function(EBAComboSearchNewRecords,list){
			setSelectedRowByKey(list._syx.dhtmlObj,list._syx.lastKey);
		});
	}
}

function getComboState(stateEl)
{
	var lastKey = getSelectedRowKey(this.dhtmlObj);
	if((lastKey == null || lastKey.length == 0) && this.lastKey != null)
		lastKey = this.lastKey;
	//stateEl.setAttribute('selected', lastKey);
	stateEl.setAttribute('selected', this.dhtmlObj.GetList().GetSelectedRowIndex());
}
";

		protected static string s_perControlScript = @"<script>
{4}
combos[combos.length] = '{1}';

ComboRowSelected{0} = function()
{{
	if({6})
		{2};
	else
	{{
		var combo = nitobi.getComponent('{5}');
		{3}
	}}	
}}
</script>";

		protected static string s_updateTriggerScript = "bizProcManager.triggerEvent(null, new EventInfo('{0}', 'bizObjFieldSelected', combo.GetSelectedRowValues()[0]));";
		protected static string s_triggerScript = "{0}BizProc.triggerEvent('{1}', 'bizObjSelected', combo.GetSelectedRowValues()[0]);";
		protected static string s_registerScript = @"
{0}Setup = function()
{{
	var combo = nitobi.getComponent('{0}');
{2}
	combo.SetTextValue('{3}');
	setSelectedRowByKey(combo, '{1}');
}}
";
		protected static string s_innerRegisterScript = @"
	var cctl = new ClientControl(combo, setComboState, getComboState);
	cctl.id = '{1}';
	cctl.displayField = '{2}';
	{0}BizProc.addClientControl(cctl);
";


		public class ExtendedNitobiCombo : Nitobi.Combo
		{
			protected NitobiComboBoxBizObjListDisplay m_parent = null;

			public ExtendedNitobiCombo(NitobiComboBoxBizObjListDisplay parent)
			{
				m_parent = parent;
			}
			public string CompressedXml { get { return GetDataSourceCompressedXml(); } }
			protected override string GetDataSourceCompressedXml()
			{
				if (m_parent.LiveScroll)
					return base.GetDataSourceCompressedXml();

				string bizRule = m_parent.DataSourceBizRule;
				bool comboStyle = true;
				int startIndex = 0;
				int numRows = -1;
				string namespaceUri = "http://www.nitobi.com";
				XmlDocument doc = new XmlDocument();
				XmlElement dataEl = null;
				string columnNames = m_parent.ColumnNames;
				string[] columnNameArray = columnNames.Split('|');


				IBizObjList bizobjs = m_parent.BizObjs;
				if (!comboStyle)
				{
					ActiveBizProc bizproc = m_parent.BPC.getActiveBizProc(m_parent.State.ParentBizProcIds[0]);
					doc.LoadXml(string.Format(@"
	<ntb:grid xmlns:ntb='http://www.nitobi.com'><ntb:datasources><ntb:datasource id='{0}'></ntb:datasource></ntb:datasources></ntb:grid>", bizproc.OfflineState.Id));
					XmlElement dsEl = doc.DocumentElement.ChildNodes[0].ChildNodes[0] as XmlElement;
					XmlElement dssEl = doc.CreateElement("ntb", "datasourcestructure", namespaceUri);
					dsEl.AppendChild(dssEl);
					dssEl.SetAttribute("fieldnames", columnNames); //string.Join("|", active.ColumnNames));
					dataEl = doc.CreateElement("ntb", "data", namespaceUri);
					dsEl.AppendChild(dataEl);
				}	
				else
				{
					string baseXml = String.Format("<xml id='{0}XmlDataSource'><root fields='{1}' keys='{2}' xml:lang='en' types='' /></xml>",
						this.ClientID, columnNames, bizobjs.objectType.KeyFieldNames);
					doc.LoadXml(baseXml);
					dataEl = doc.SelectSingleNode("xml/root") as XmlElement;
					namespaceUri = null;
				}

				if (bizobjs != null)
					for (int pos = startIndex; pos < bizobjs.numElements && ((numRows <= 0) ? true : pos < (pos + numRows)); ++pos)
					{
						XmlElement eEl = doc.CreateElement("ntb", "e", namespaceUri);
						char aName = 'a';
						foreach (string name in columnNameArray)
							eEl.SetAttribute((aName++).ToString(), bizobjs[pos].get(name) == null?"":bizobjs[pos].get(name).ToString());

						if (!comboStyle)
							eEl.SetAttribute("xi", pos.ToString());
						else
						{
							eEl.SetAttribute("fld", "");
							eEl.SetAttribute("xk", (pos + 1).ToString());
						}
						dataEl.AppendChild(eEl);
					}
				string xml = doc.OuterXml;
				return xml;
			}
		}
	}
}
